using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

using System.Diagnostics;
using Hoshimi._Utilitaire_;

namespace Hoshimi
{
    public class Group : Unit, IBotOwner
	{
		#region Variables
		
		public List<Unit> mChilds			= new List<Unit>();
        protected int mDemandInProgress		= 0;

		#endregion

		#region Getters & Setters

        public int myDemandInProgress	{ get { return this.mDemandInProgress; } }
		public List<Unit> myChilds		{ get { return this.mChilds; } }
		public override bool IsGroup	{ get { return true; } }

		#endregion

		#region Ctor

		// Inhibate the default constructor
		protected Group() {}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="player">Environment</param>
		/// <param name="aFactory">Factory used to build the state machine</param>
		public Group(Component myFather, AbstractSMFactory aFactory ) 
            : base(myFather, aFactory ) 
        { 

        } 

		#endregion
 
		#region Methods

		public virtual float GetFreeRate() { return 0f; }

		public virtual bool ReleaseUnit() { return false; }

		// Add a unit to the group
		public override bool Add( Unit unit ) 
		{
			if (unit == null)
			{
				return false;
			}

			// We affect a father to the unit
			unit.myFather = this;

			myChilds.Add( unit );

			return true;
		}

		/// <summary>
		/// Remove a unit (and clear his specifics values)
		/// </summary>
		/// <param name="unit"></param>
		/// <returns></returns>
		public override bool Remove( Unit unit ) 
		{
			myChilds.Remove( unit );

			if (unit == null)
			{
				return true;
			}

			if(unit.myFather == this)
			{
				unit.myFather = null;
			}

			return true;
		}

        /// <summary>
		/// Release all units
		/// </summary>
		public void ReleaseAllUnits()
		{
			while ( myChilds.Count > 0 )
			{
				this.Remove( myChilds[ 0 ] );
			}
		}

		public void ReleaseAllBots()
		{
			while ( myChilds.Count > 0 )
			{
				myBotManager.DeclareReleasedBot((Bot) myChilds[ 0 ]);

				this.Remove(myChilds[ 0 ] );
			}
		}

		public virtual int GetFreeBotCount()
		{
			return 0;
		}

		/// <summary>
		/// Play the group's decision turn (and all of child's turn. Override the normal method
		/// </summary>
		/// <returns>Returns true if the state has blocked the unit for this (and only this) turn</returns>
		public override bool Play() 
		{
			// We clean dead bot
			this.IsAlive();
		
			bool returnValue = base.Play();

			Unit unit;
			int i = 0;
			// Boucle while() pour permettre la supression d'enfant
			while(i < this.myChilds.Count)
			{
				unit		= this.myChilds[i];
				returnValue = unit.Play() && returnValue;

				i++;
			}

			return returnValue;
		}

		/// <summary>
		/// Check the life of the unit
		/// </summary>
		/// <returns>Return true if alive, otherwise false and tidy</returns>
		public override bool IsAlive()
		{
			int i = 0;
			while ( i < myChilds.Count ) 
			{
				Unit unit = myChilds[ i ];
				if ( !unit.IsAlive() ) 
				{
					myChilds.RemoveAt( i );
				} 
				else 
				{
					i++;
				}
			}

			return myChilds.Count > 0;
		}

		#endregion

		#region Remove dead bots

        protected bool RemoveDeadBot(List<Bot> botList)
        {
            int botCount = botList.Count;
            int i = 0;
			while ( i < botList.Count ) 
			{
				
                Bot bot = botList[ i ];
				if ( !bot.IsAlive() ) 
				{
					botList.RemoveAt( i );
				} 
				else 
				{
					i++;
				}
			}

            return (botList.Count < botCount);
        }

        protected bool RemoveDeadBotFromUniqueNavigation<DictonaryValueType>(Dictionary<Bot, DictonaryValueType> dictionary)
        {
            int botCount = dictionary.Count;

            Queue<Bot> deadBot = new Queue<Bot>();
            Bot bot;
            foreach (KeyValuePair<Bot, DictonaryValueType> kvp in dictionary)
            {
                bot = kvp.Key;

                if (bot.IsAlive())
                {
                    continue;
                }

                deadBot.Enqueue(bot);
            }

            while (deadBot.Count > 0)
            {
                dictionary.Remove(deadBot.Dequeue());
            }

            return (dictionary.Count < botCount);
        }

		public UnitType SetToNullIfDead<UnitType>(UnitType unit) where UnitType : Unit
		{
			if (unit == null || !unit.IsAlive())
			{
				return null;
			}

			return unit;
		}

		#endregion

		#region Give units
		
		public bool GiveUnitToFather(Unit unit)
		{
			if (this.myFather == null)
			{
				return false;
			}

			return this.myFather.Add(unit);
		}

		public void TryGiveAllUnitsToFather()
		{
			int i = 0;
			while(i < myChilds.Count)
			{

				if (this.GiveUnitToFather(myChilds[i]))
				{
					this.Remove(myChilds[i]);
				}
				else
				{
					i++;
				}				
			}
		}

		public void TryGiveAllBotsToFatherBeforeRelease()
		{
			this.TryGiveAllUnitsToFather();
			this.ReleaseAllBots();
		}

		public bool GiveUnitToChilds(Unit unit)
		{
			foreach(Unit child in this.myChilds)
			{
				if(child.Add(unit))
				{
					return true;
				}
			}

			return false;
		}

		#endregion

        #region IBotOwner Members

		public virtual Point GetDemandLocation()
		{
			return myStrategyManager.InjectionPoint;
		}

		public virtual void InitGroup()
		{

		}

        public void AskBot(BotTypeEnum botType)
        {
			this.AskBot(botType, false, true, false, false);
        }

		public void AskBot(BotTypeEnum botType, bool inEmergency, bool tryUseFreeBot, bool forceUseIPCreator, bool forceUseDefaultIP)
        {
            this.mDemandInProgress++;
            myBotManager.AskBot(botType, this, inEmergency, tryUseFreeBot, forceUseIPCreator, forceUseDefaultIP);
			
			if(Config.LogAskedBot)
			{
				myPlayer.PrintLog("Group : Demande de " + botType.ToString() + " par " + this.ToString());
			}
		}

		public void RemoveAskedBot(BotTypeEnum botType)
        {
            if(this.mDemandInProgress > 0)
			{
				this.mDemandInProgress--;
			}
            myBotManager.RemoveAskedBot(botType);

			if(Config.LogAskedBot)
			{
				myPlayer.PrintLog("Group : Suppression de la demande de " + botType.ToString() + " par " + this.ToString());
			}
		}

        public bool AffectBot(Bot bot)
        {
            if(this.mDemandInProgress > 0)
			{
				this.mDemandInProgress--;
			}
            return this.Add(bot);
        }

		public bool TryAffectBot(BotTypeEnum botType)
		{
			this.mDemandInProgress++;
			if(!myBotManager.TryAffectFreeBot(botType, this))
			{
				if(this.mDemandInProgress > 0)
				{
					this.mDemandInProgress--;
				}
				return false;
			}
			return true;
		}

        #endregion
	}
}
